// import com.alibaba.druid.DbType;
// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
// import com.alibaba.druid.sql.dialect.oracle.ast.OracleSQLObject;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;
// import com.alibaba.druid.util.FnvHash;

// import java.io.IOException;
// import java.util.ArrayList;
// import java.util.List;
#pragma once

#include <string>
#include <list>

#include "../SQLExpr.h"
#include "../SQLDataType.h"
#include "../SQLObjectImpl.h"
#include "../SQLReplaceable.h"

#include "../expr/SQLIntegerExpr.h"

class SQLASTVisitor;

class SQLSelectItem : virtual public SQLObjectImpl, virtual public SQLReplaceable
{
public:
  static string_ptr class_;
  SQLExpr_ptr expr;
  string_ptr alias;

  bool connectByRoot;
  long aliasHashCode64;
  string_list_ptr aliasList;

  SQLSelectItem();

  SQLSelectItem(SQLExpr_ptr expr);

  SQLSelectItem(int value);

  SQLSelectItem(SQLExpr_ptr expr, string_ptr alias);

  SQLSelectItem(SQLExpr_ptr expr, string_ptr alias, bool connectByRoot);

  SQLSelectItem(SQLExpr_ptr expr, string_list_ptr aliasList, bool connectByRoot);

  SHAREDOBJECT(SQLSelectItem) ;
  GETCALSS(SQLSelectItem);
  SQLExpr_ptr getExpr();

  void setExpr(SQLExpr_ptr expr);
  void setExpr(SQLObject_ptr expr);
  string_ptr computeAlias();

  SQLDataType_ptr computeDataType();

  string_ptr getAlias();

  string_ptr getAlias2();

  void setAlias(string_ptr alias);

  // void output(Appendable buf) {
  //     try {
  //         if (this->connectByRoot) {
  //             buf.append(" CONNECT_BY_ROOT ");
  //         }
  //         this->expr->output(buf);
  //         if ((this->alias != NULL) && (this->alias.length() != 0)) {
  //             buf.append(" AS ");
  //             buf.append(this->alias);
  //         }
  //     } catch (IOException ex) {
  //         throw new FastsqlException("output error", ex);
  //     }
  // }

  virtual void accept0(SQLASTVisitor_ptr v) override;

  // BOOL_ptr equals(Object_ptr  o) {
  //     if (this == o) {
  //         return BOOL::TRUE;
  //     }
  //     if (o == NULL || getClass() != o->getClass()) {
  //         return BOOL::FALSE;
  //     }

  //     SQLSelectItem* that = (SQLSelectItem_ptr ) o;

  //     if (connectByRoot != that->connectByRoot) {
  //         return BOOL::FALSE;
  //     }
  //     if (alias_hash() != that->alias_hash()) {
  //         return BOOL::FALSE;
  //     }
  //     if (expr != NULL ? !expr->equals(that->expr) : that->expr != NULL) {
  //         return BOOL::FALSE;
  //     }

  //     return aliasList != NULL
  //             ? aliasList->equals(that->aliasList)
  //             : that->aliasList == NULL;
  // }

  // int hashCode() {
  //     int result = expr != NULL ? expr->hashCode() : 0;
  //     result = 31 * result + (!alias.empty() ? alias.hashCode() : 0);
  //     result = 31 * result + (connectByRoot ? 1 : 0);
  //     result = 31 * result + (int) (alias_hash() ^ (alias_hash() >>> 32));
  //     result = 31 * result + (aliasList != NULL ? aliasList.hashCode() : 0);
  //     return result;
  // }

  bool isConnectByRoot();

  void setConnectByRoot(bool connectByRoot);

  virtual SQLObject_ptr clone();

  BOOL_ptr replace(SQLExpr_ptr expr, SQLExpr_ptr target);

  BOOL_ptr match(string_ptr alias);

  long alias_hash();

  BOOL_ptr match(long alias_hash_);

  string_list_ptr getAliasList();

  // string_ptr  toString() {
  //     DbType dbType = NULL;
  //     if (parent instanceof OracleSQLObject) {
  //         dbType = DbType.oracle;
  //     }
  //     return SQLUtils.toSQLString(this, dbType);
  // }

  // BOOL_ptr isUDTFSelectItem() {
  //     return aliasList != NULL && aliasList.size() > 0;
  // }

  bool containsAttribute(string_ptr name){};
  void addBeforeComment(string_list_ptr comments){};
  string_list_ptr getAfterCommentsDirect(){};
  string_list_ptr getBeforeCommentsDirect(){};
  void addAfterComment(string_ptr comment){};
  void addAfterComment(string_list_ptr comments){};
  void addAfterComment(wstring_list_ptr comments){};
  bool hasBeforeComment(){};
  bool hasAfterComment(){};
};
